﻿using System.Reflection;
using System.Security.Cryptography;
using System.Text;

using AntDesign;

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;

using MyDocuments.Shared;

namespace MyDocuments.Server.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class FileController : ControllerBase
    {
        private readonly long _fileSizeLimit = 2097152;
        private readonly string[] _permittedExtensions = { ".gif", ".png", ".jpg", ".jpeg" };
        private readonly string _targetFolderPath;
        private readonly string _pwd;
        const string pwdPath = "./pwds.ini";

        public FileController(IConfiguration config)
        {
            var assembly = Assembly.GetExecutingAssembly();
            //_targetFolderPath = Path.GetDirectoryName(assembly.Location)!;
            _targetFolderPath = Path.Combine(Path.GetDirectoryName(assembly.Location)!, "Uploads");
            Directory.CreateDirectory(_targetFolderPath);

            if (!System.IO.File.Exists(pwdPath))
            {
                System.IO.File.Create(pwdPath).Dispose();

                _pwd = Utils.ConvertMd5(string.Format("{0}_{1}_{2}",
                                        new Random()
                                        .NextInt64(111111111111, 999999999999),
                                        new Random()
                                        .NextInt64(123456789, 987654321),
                                        DateTime.Now.Ticks
                                        ));


                System.IO.File.WriteAllText("./pwds.ini", _pwd);
            }

            Utils.BasePwd = System.IO.File.ReadAllText(pwdPath);
        }

        [HttpGet]
        public IEnumerable<FileNames> Get()
        {
            Utils.LastResult = new List<FileNames>();
            var result =  Utils.GetallDirectory(new List<FileNames>(), Utils.BasePath);
            return result;
        }

        [HttpGet("s/{search}")]
        public IEnumerable<FileNames> Gets(string search)
        {
            var result = Utils.GetallDirectoryBySearch(new List<FileNames>(), Utils.BasePath, search.ToLower());
            return result;
        }

        [HttpGet("Content/{path}")]
        public string Get(string path)
        {
            path = Uri.UnescapeDataString(path);
            return System.IO.File.ReadAllText(Utils.BasePath + path);
        }

        [HttpPost("Content")]
        public string Post(FileSave fileSave)
        {
            fileSave.FileName = Utils.BasePath + fileSave.FileName;

            switch (fileSave.Type)
            {
                case FileSaveEnum.Create:
                    System.IO.File.Create(fileSave.FileName).Dispose();
                    break;
                case FileSaveEnum.ReName:
                    fileSave.Value = Utils.BasePath + fileSave.Value;
                    System.IO.File.Move(fileSave.FileName, fileSave.Value);
                    break;
                case FileSaveEnum.ReNameFolder:
                    fileSave.Value = Utils.BasePath + fileSave.Value;
                    System.IO.Directory.Move(fileSave.FileName, fileSave.Value);
                    break;
                case FileSaveEnum.Delete:
                    System.IO.File.Delete(fileSave.FileName);
                    break;
                case FileSaveEnum.DeleteFolder:
                    System.IO.Directory.Delete(fileSave.FileName, true);
                    break;
                case FileSaveEnum.CreateFolder:
                    System.IO.Directory.CreateDirectory(fileSave.FileName);
                    break;
                case FileSaveEnum.Modify:
                default:
                    System.IO.File.WriteAllText(fileSave.FileName, fileSave.Value);
                    break;
            }
            return "ok";
        }

        /// <summary>
        /// Uploads a file.
        /// </summary>
        /// <returns></returns>
        [HttpPost("Upload")]
        public async Task<IActionResult> Upload()
        {
            var boundary = HeaderUtilities.RemoveQuotes(Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;

            var reader = new MultipartReader(boundary, HttpContext.Request.Body);
            var section = await reader.ReadNextSectionAsync();

            string trustedFileNameForFileStorage = String.Empty;

            while (section != null)
            {
                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition,
                    out var contentDisposition);

                if (hasContentDispositionHeader)
                {
                    if (contentDisposition.IsFileDisposition())
                    {
                        // Don't trust the file name sent by the client. To display the file name, HTML-encode the value.
                        var trustedFileNameForDisplay = System.Net.WebUtility.HtmlEncode(contentDisposition.FileName.Value);
                        trustedFileNameForFileStorage = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()) +
                                Path.GetExtension(trustedFileNameForDisplay);

                        var streamedFileContent = await FileHelpers.ProcessStreamedFile(section, contentDisposition,
                            ModelState, _permittedExtensions, _fileSizeLimit);

                        if (!ModelState.IsValid)
                            return BadRequest(ModelState);

                        var trustedFilePath = Path.Combine(_targetFolderPath, trustedFileNameForFileStorage);
                        using (var targetStream = System.IO.File.Create(trustedFilePath))
                        {
                            await targetStream.WriteAsync(streamedFileContent);
                        }
                    }
                }

                // Drain any remaining section body that hasn't been consumed and read the headers for the next section.
                section = await reader.ReadNextSectionAsync();
            }

            if (!string.IsNullOrEmpty(trustedFileNameForFileStorage))
            {
                int index = FileHelpers.GetExtensionId(Path.GetExtension(trustedFileNameForFileStorage));
                return Ok($"/download/{index}/{Path.GetFileName(trustedFileNameForFileStorage)}");
            }
            else
                return BadRequest("It wasn't possible to upload the file");
        }

        [HttpGet("pwd/{path}")]
        public FileSave? GetPWD(string path)
        {
            var file = Utils.GetFileByPwd(path);
            if (file == null) { return null; }
            return new FileSave
            {
                FileName = file.Name,
                Value = System.IO.File.ReadAllText(Utils.BasePath + file.Path)
            };
        }
    }
}
